var random = function(min, max) {
    return Math.random() * (max - min) + min
}

var distance = function (x1, y1, x2, y2) {
    return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

var w;//= c.width = window.innerWidth;
var h;//= c.height = window.innerHeight;
var ctx;// = c.getContext("2d");
var zoomBase = 1.0, zoomStep = Math.sqrt(2.0);// = document.getElementById('zoom').value;
var particles = [], eternal, ETERNAL_ID;
var bombs = [];
var anim, refreshPad, initOrbs, updateOrbs, findBigger;
var timesCalced = 0, cps = 0, startTimestamp = 0, nowTimestamp = 1, calcStep = 0;//1.414213562373;

var visionOffsetX = 0, visionOffsetY = 0; //视野区域的便宜
var containerBorderX = 20000, containerBorderY = 20000;

var hue = Math.random()*100+20;
// 万有引力系数 G 决定引力大小
var G       = 0.000021; //bigger, the gravity is bigger
var ConstR  = 0.0004; //bigger, the repulsion is bigger, the unreachable radius is bigger.
var ConstR2 = 0.85; //bigger, the faster velo will be more resisted
//G = 0.1;

var clearColor = "rgba(15, 15, 15, .2)";
var urlParam = new UrlSearch(); //实例化

// 可配置参数
var maxParticles = urlParam.get('maxParticles') || 10;
var calcTimes = urlParam.get('calcTimes') || 400;
var enableCenter = urlParam.get('enableCenter') ? 1 : 0;
var orbMinMass = urlParam.get('orbMinMass');
var orbMaxMass = urlParam.get('orbMaxMass');
var centerMass = urlParam.get('centerMass');
var orbMaxVelo = urlParam.get('orbMaxVelo', 'float');
var arrangeType  = urlParam.get('arrangeType');
var stats = new Stats();


window.onload = function () {
    window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;

    var c = document.getElementById("canvas-club");
    w= c.width = window.innerWidth;
    h = c.height = window.innerHeight;
    ctx = c.getContext("2d");
    ctx.globalCompositeOperation = "source-over";
    ctx.shadowBlur = 0;
    ctx.fillStyle = clearColor;
    ctx.shadowColor = clearColor;
    zoomBase = document.getElementById('zoom').value;
    startTimestamp = new Date().getTime();//当前毫秒时间戳
    //console.log(urlParam.get('enableCenter', 'ori'));
    //console.log(enableCenter);

    window.addEventListener("resize", function() {
        w = c.width = window.innerWidth;
        h = c.height = window.innerHeight;
    });

    var statspannel = document.getElementById("statspannel");
    statspannel.appendChild(stats.domElement);


    initOrbs = function(num) {
        particles = [];
        for (var i = 1; i <= num; i++) {
            //setTimeout(function() {
                var p = new Orb();
                p.id = particles.length;
                p.init();
                // p.mass = random(orbMinMass, orbMaxMass);//平均分布
                p.mass = random(1, 10000)/10000 * (Math.pow(((i+1)/(num+1)), 3.0) * (orbMaxMass-orbMinMass) + orbMinMass);//正态分布，趋于小
                tangle = i*Math.PI/num*2.0;
                switch (arrangeType) {
                    case 2:
                        p.vx =  Math.sin(tangle) * orbMaxVelo;
                        p.vy = -Math.cos(tangle) * orbMaxVelo;
                        p.x = Math.cos(tangle) * 800.0 + w/2.0;
                        p.y = Math.sin(tangle) * 800.0 + h/2.0;
                        break;
                    default:
                        var tdir = Math.random()*2.0*Math.PI, trandom = Math.random();
                        p.vx = random(-orbMaxVelo, orbMaxVelo);// Math.sin(vdir) * orbMaxVelo;// 
                        p.vy = random(-orbMaxVelo, orbMaxVelo);//-Math.cos(vdir) * orbMaxVelo;// 
                        // 圆形区域分布
                        p.x = trandom*8000.0 * Math.cos(tdir) + w/2.0;//random(w/3.0, w/3.0*2);//Math.cos(tangle) * 300.0 + w/2.0;//
                        p.y = trandom*8000.0 * Math.sin(tdir) + h/2.0;//random(h/3.0, h/3.0*2);//Math.sin(tangle) * 300.0 + h/2.0;//
                        //console.log('h='+h+' w='+w+' p.x='+p.x+' p.y='+p.y);
                        break;
                }
                if (i == 1) {
                    // p.mass *= 100;
                }
                p.size = Math.pow(p.mass, 0.2) 
                particles.push(p);
                //console.log(i);
            //}, i * 50);
        }


        eternal = new Orb();//new EternalStar();
        //eternal.init();
        ETERNAL_ID = particles.length;
        eternal.id = particles.length;
        eternal.mass = centerMass;
        eternal.x = w/2;
        eternal.y = h/2;
        eternal.size = Math.pow(eternal.mass, 0.2) ;//2.5;

        enableCenter && particles.push(eternal);
    }

    updateOrbs = function(nTimes) {
        nTimes = nTimes || calcTimes;
        
        for (var k=0; k<nTimes; ++k) {
            for (var i=0; i<particles.length-1; ++i) {
                var p = particles[i];
                //console.log(i);
                //if (p.id != ETERNAL_ID) {
                    //最后一颗恒星不计算位移,不移动
                    p.update(particles);
                //}
            }
            timesCalced += particles.length * particles.length;
        }
    }

    findBigger = function(nTimes) {
        // find neigher witch bigger than me
        nTimes = nTimes || calcTimes;
        
            for (var i=0; i<particles.length-1; ++i) {
                var p = particles[i];
                p.findBiggerDot(particles);
            }
            timesCalced += particles.length * particles.length;
    }

    anim = function() {
        ++calcStep;
        // updateOrbs(calcTimes);
        findBigger(1);

        stats.update();
        ctx.fillRect(0, 0, w, h);
        //ctx.lineWidth = 1;
        //ctx.beginPath();
        
        //mouse.move();

        for (var i in particles) {
            var p = particles[i];
            p.draw(ctx);
            if (p.lifeStep==2) {
                var bomb = new Bomb(p.x, p.y, p.hue);
                bomb.pid = p.id;
                bomb.init();
                bombs.push(bomb);
                //console.log('BOMBED,p.id='+p.id);
                p.lifeStep = 3;
                //i--;
                refreshPad();
            }
        }
        //ctx.closePath();
        //ctx.stroke();
        
        for (var i in bombs) {
            var b = bombs[i];
            b.draw(ctx);
        }

        //draw container border start
        // ctx.strokeStyle = "hsla(0, 90%, 50%, 1)";
        // ctx.beginPath();
        // ctx.arc(w/2+visionOffsetX, h/2+visionOffsetY, containerBorderX*zoomBase, 0, Math.PI*2 , false); 
        // ctx.closePath();
        // ctx.stroke();
        //draw container border end

        //console.log(nTimes+' times done.');
        //refreshPad();
        hue+=29;
        hue %= 16000000;
        //mouse.draw();
        //eternal.draw();
        //requestAnimationFrame(anim);
        if (calcStep %20 == 19) {
            // 计算cps
            nowTimestamp = new Date().getTime();
            var timeUsed = nowTimestamp - startTimestamp;
            cps =  timesCalced/ (timeUsed/1000.0);
            document.getElementById('cps').innerHTML = cps.toFixed(2);

            timesCalced = 0;
            startTimestamp = nowTimestamp-1;
        }
    }

    refreshPad = function() {
        // 清理多余的particles
        for (var i=0; i<particles.length; ++i) {
            if (particles[i].lifeStep==3) {
                particles.splice(i, 1);
                --i;
            }
        }
        // 清理多余的爆炸碎屑
        for (var i=0; i<bombs.length; ++i) {
            if (bombs[i].lifetime>=bombs[i].maxLifetime) {
                bombs.splice(i, 1);
                --i;
            }
        }
        // 刷新面板
        document.getElementById('livedOrbCount').innerHTML = particles.length;
        if (enableCenter) {
            document.getElementById('centerMassShow').innerHTML = eternal.mass.toFixed(2);
        }
            
        // 计算完之后清楚
        //console.log('now='+particles.length+' b='+bombs.length);
        requestAnimationFrame(refreshPad);
    }

    //anim();


    $(function(){
        $('#zoom_up').on('click', function() {
            zoomBase = zoomBase*zoomStep;
            visionOffsetX = visionOffsetX*zoomStep
            visionOffsetY = visionOffsetY*zoomStep
            $('#zoom').val(zoomBase);
        });
        $('#zoom_down').on('click', function() {
            zoomBase = zoomBase/zoomStep;
            visionOffsetX = visionOffsetX/zoomStep
            visionOffsetY = visionOffsetY/zoomStep
            $('#zoom').val(zoomBase);
        });
        $('#move_up').on('click', function() {
            visionOffsetY = visionOffsetY + 100;
        });
        $('#move_down').on('click', function() {
            visionOffsetY = visionOffsetY - 100;
        });
        $('#move_left').on('click', function() {
            visionOffsetX = visionOffsetX + 100;
        });
        $('#move_right').on('click', function() {
            visionOffsetX = visionOffsetX - 100;
        });
        $('#move_reset').on('click', function() {
            visionOffsetX = 0;
            visionOffsetY = 0;
        });
        $('#clear_msg').on('click', function() {
            $('#logpannel').html('');
        });
        $('#show_list').on('click', function() {
            let msg = '';
            let vxa = 0, vya = 0;
            let vxm = 0, vym = 0;
            let allme = 0; //kinetic energy, momentum
            for (let i=0; i<particles.length; i++) {
                let p = particles[i];
                msg += 'id:'+p.id+',x:'+p.x.toFixed(4)+',y:'+p.y.toFixed(4)+',vx:'+p.vx.toFixed(4)+',vy:'+p.vy.toFixed(4)+',m:'+p.mass.toFixed(4)+',a:'+(p.vx*p.vx+p.vy*p.vy).toFixed(8)+',resist:'+(p.resistance)+'<br>';
                vxa += p.vx;
                vya += p.vy;
                if (Math.abs(p.vx) > vxm) {
                    vxm = Math.abs(p.vx);
                }
                if (Math.abs(p.vy) > vym) {
                    vym = Math.abs(p.vy);
                }
                allme += (p.vx*p.vx+p.vy*p.vy);
            }
            vxa = vxa/particles.length;
            vya = vya/particles.length;
            
            if (particles.length>0) {
                msg = 'avg velo:'+vxa.toFixed(4) + ', '+vya.toFixed(4)+',  max velo:'+vxm.toFixed(4)+', '+vym.toFixed(4)+', avga:'+(allme/(particles.length)).toFixed(8)+'<br>'+msg;
            }
            $('#logpannel').html(msg);
        });
        document.body.onmousewheel = function(event, delta) {
            event = event || window.event;
            var etype = event.type;
            if (etype == 'DOMMouseScroll' || etype == 'mousewheel') {
                event.delta = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
            }
            if (event.delta > 0) {
                zoomBase = zoomBase*zoomStep;
                visionOffsetX = visionOffsetX*zoomStep
                visionOffsetY = visionOffsetY*zoomStep
                lastVisionOffsetX = lastVisionOffsetX*zoomStep
                lastVisionOffsetY = lastVisionOffsetY*zoomStep
            } else {
                zoomBase = zoomBase/zoomStep;
                visionOffsetX = visionOffsetX/zoomStep
                visionOffsetY = visionOffsetY/zoomStep
                lastVisionOffsetX = lastVisionOffsetX/zoomStep
                lastVisionOffsetY = lastVisionOffsetY/zoomStep
            }
            $('#zoom').val(zoomBase);
            //console.log(event);	
        };
        var box=document.querySelector('#canvas-club');
        var isDragStatus = 0;
        var dragStartX, dragStartY;
        var offLX, offLY;
        var lastVisionOffsetX = 0, lastVisionOffsetY = 0;
        box.onmousedown=function(e){
            isDragStatus=1;              //鼠标按下才能触发onmousemove方法

            // var tmpx=e.clientX;     //鼠标点击的坐标值，x
            // var tmpy=e.clientY;
            // var left= this.style.left;
            // left=left.substr(0,left.length-2);   //去掉px
            // var top=this.style.top;
            // top=top.substr(0,top.length-2);
            // dragStartX=parseInt(tmpx-left);
            // dragStartY=parseInt(tmpy-top);
            // dragStartX=dragStartX*zoomBase;
            // dragStartY=dragStartY*zoomBase;
            // dragStartX = e.movementX;
            // dragStartY = e.movementY;

            // //获取鼠标当前坐标 
			// let pageX = e.clientX;
			// let pageY = e.clientY;
			// //获取block的坐标，左边界和上边界 
			// let offX = parseInt(this.style.left) || 0;
			// let offY = parseInt(this.style.top) || 0;
			// //计算出鼠标坐标相对于block坐标的间距 
			// offLX = pageX - offX;
            // offLY = pageY - offY;
            console.log('mouse down at:'+e.clientX+','+e.clientY+' visionOffset='+visionOffsetX+','+visionOffsetY);
            
            dragStartX = e.clientX;
            dragStartY = e.clientY;
            box.onmousemove=function(e){
                if(isDragStatus===1){
                    console.log('mouse up draging:'+e.clientX+','+e.clientY+' visionOffset='+visionOffsetX+','+visionOffsetY);
                    visionOffsetX =lastVisionOffsetX+(e.clientX-dragStartX);
                    visionOffsetY =lastVisionOffsetY+(e.clientY-dragStartY);
                    // visionOffsetX +=(e.clientX-dragStartX)*zoomBase;
                    // visionOffsetY +=(e.clientY-dragStartY)*zoomBase;
                    // visionOffsetX =(e.clientX-offLX);
                    // visionOffsetY =(e.clientY-offLY);
                }
            };
        };
        box.onmouseup=function(e){
            console.log('mouse up drag over at:'+e.clientX+','+e.clientY+' visionOffset='+visionOffsetX+','+visionOffsetY);
            isDragStatus=0;
            box.onmousemove = null;
            lastVisionOffsetX = visionOffsetX;
            lastVisionOffsetY = visionOffsetY;
        };

    })


    initOrbs(maxParticles);
    refreshPad();
    //setTimeout('updateOrbs(calcTimes*100000000)', 100);
    setInterval('anim()', 40);

}


/**
 * [drawradientLine 画颜色线性变化的线条]
 * @param  number x1        [起点x坐标]
 * @param  number y1        [起点y坐标]
 * @param  number x2        [终点x坐标]
 * @param  number y2        [终点y坐标]
 * @param  number lineWidth [线条宽度]
 * @param  []colors colors    [颜色数组，均匀分布的]
 * @return null           [无]
 * @usage drawradientLine(ctx, 10, 10, 10+500, 10, 50, ['red', 'yellow', 'green', 'orange', '#FF00FF']);
 */
var drawradientLine = function (ctx, x1, y1, x2, y2, lineWidth, colors) {
    ctx.beginPath(); // 开始路径，如果没有这个和结束路径包围，所有线条都是最后那根线条的样式了
    ctx.moveTo(x1, y1); // 开始位置
    ctx.lineTo(x2, y2); // 画到此处
    if (lineWidth > 0) {
        ctx.lineWidth = lineWidth;
    }

    let grd = ctx.createLinearGradient(x1, y1, x2, y2); //线性渐变的起止坐标
    for (let i=0; i<colors.length; i++) {
        grd.addColorStop(i / colors.length, colors[i]);
    }
    ctx.strokeStyle = grd;

    ctx.closePath(); // 结束路径，应与开始路径呼应(会不会导致内存泄露跟实现有关系)
    ctx.stroke();
}

